<?php

namespace App\Http\Controllers;

use App\Events\BuyChange;
use App\Events\NoticeChange;
use App\Events\Took;
use App\Models\Buy;
use App\Models\Cancel;
use Illuminate\Http\Request;

class BuyController extends Controller
{
  public function indexForAdmin(Request $request)
  {
    $page = $this->indexForAdminQuery($request)
      ->page();

    return success($page);
  }

  protected function indexForAdminQuery($request)
  {
    return Buy::latest()->with('member', 'seller')
      ->when($request->has('seller_code'), function ($q) use ($request) {
        $q->whereHas('seller', function ($q) use ($request) {
          $q->where('code', $request->seller_code);
        });
      })
      ->when($request->has('seller_username'), function ($q) use ($request) {
        $q->whereHas('seller', function ($q) use ($request) {
          $q->where('username', $request->seller_username);
        });
      })
      ->when($request->has('id'), function ($q) use ($request) {
        $q->where('id', $request->id);
      })
      ->when($request->has('id'), function ($q) use ($request) {
        $q->where('id', $request->id);
      })
      ->when($request->has('member_username'), function ($q) use ($request) {
        $q->whereHas('member', function ($q) use ($request) {
          $q->where('username', $request->member_username);
        });
      })
      ->when($request->has('created_at'), function ($q) use ($request) {
        $range = getRange($request->created_at);
        $q->whereBetween('created_at', $range);
      }, function ($q) {
        // $q->today();
      });
  }

  public function timeoutIndexForAdmin(Request $request)
  {
    $limit = now()->subMinutes(sys('buy_waiting_max_minutes'));
    $page = $this->indexForAdminQuery($request)
      ->where('state', 'waiting')
      ->where('created_at', '<', $limit)
      ->page();

    return success($page);
  }

  public function indexForMember(Request $request)
  {
    $page = Buy::select('id', 'state', 'coins', 'bank', 'bankcard', 'realname', 'fee', 'tip', 'updated_at', 'freeze_at')
      ->when($request->has('state'), function ($q) use ($request) {
        $q->where('state', $request->state)
          ->where('member_id', auth()->id());
      }, function ($q) {
        $q->where('state', 'waiting');
      })
      ->orderBy('created_at', 'asc')
      // ->with('seller:id,username,avatar')
      ->latest()
      ->page(20);

    return success($page);
  }

  public function indexForAgent(Request $request)
  {
    $page = Buy::select('id', 'member_id', 'agent_id', 'coins', 'fee', 'tip', 'agent_fee', 'agent_tip', 'took_at', 'created_at', 'freeze_at', 'unfreeze_at')
      ->when($request->has('id'), function ($q) use ($request) {
        $q->where('id', $request->id);
      })
      ->when($request->has('member_username'), function ($q) use ($request) {
        $q->whereHas('member', function ($q) {
          $q->where('username', request()->member_username);
        });
      })
      ->with('member:id,pid,username')
      ->where('agent_id', auth()->id())
      ->state('unfreeze')
      ->latest()
      ->page();

    return success($page);
  }

  public function indexForSeller(Request $request)
  {
    $page = Buy::select('id', 'transaction_id', 'coins', 'seller_fee', 'seller_tip', 'bank', 'bankcard', 'realname', 'created_at', 'took_at', 'unfreeze_at', 'state')
      ->when($request->has('state'), function ($q) use ($request) {
        $q->where('state', $request->state);
      })
      // ->with('member:id,username,avatar,realname,bank,bankcard')
      ->where('seller_id', sellerId())
      ->latest()
      ->page();

    return success($page);
  }

  public function take($id)
  {
    $exists = Buy::where([
      'state' => 'took',
      'member_id' => auth()->id()
    ])->exists();
    if ($exists) {
      fail('请完成上一笔后接单');
    }
    $buy = \DB::transaction(function () use ($id) {
      $buy = Buy::lockForUpdate()->findOrFail($id);
      if ($buy->state !== 'waiting') {
        fail('状态错误');
      }

      $buy->member_id = auth()->id();
      $buy->took_at = now();
      $buy->state = 'took';
      $buy->save();
      return $buy;
    });

    event(new BuyChange($buy->seller_id, 'take', $id));

    return success('ok');
  }

  public function freeze($id)
  {
    $buy = \DB::transaction(function () use ($id) {
      $buy = Buy::lockForUpdate()->findOrFail($id);
      if ($buy->state !== 'took') {
        fail('状态错误');
      }

      $member = auth()->user();

      if ($buy->member_id !== $member->id) {
        forbidden();
      }
      $buy->fee = bcmul($buy->coins, $member->fee_ratio, 3);
      $buy->tip = $member->tip;
      $buy->deposit = bcadd($buy->coins, bcadd($buy->tip, $buy->fee, 3), 3);

      if ($member->pid) {
        $agent = $member->parent;
        $buy->agent_id = $agent->id;
        $buy->agent_fee = bcmul(bcsub($agent->fee_ratio, $member->fee_ratio, 3), $buy->coins, 3);
        $buy->agent_tip = bcsub($agent->tip, $member->tip, 2);
        $buy->agent_tip_fee = bcadd($buy->agent_tip, $buy->agent_fee, 3);
      }

      $buy->state = 'frozen';
      $buy->freeze_at = now();
      $buy->save();
      return $buy;
    });

    event(new NoticeChange());

    $buy->callback();

    return success('ok');
  }

  public function unfreeze($id)
  {
    $buy = Buy::findOrFail($id);
    if ($buy->member_id !== auth()->id()) {
      forbidden();
    }

    $buy->unfreeze();
    $buy->callback();

    return success('ok');
  }

  public function cancel($id)
  {
    $buy = \DB::transaction(function () use ($id) {
      $buy = Buy::lockForUpdate()->findOrFail($id);

      if ($buy->member_id !== auth()->id()) {
        forbidden();
      }

      $buy->cancelLog();
      $buy->clearMember();
      return $buy;
    });

    event(new BuyChange($buy->seller_id, 'cancel', $id));
    return success('ok');
  }

  public function statis()
  {
    $counts = Buy::where('member_id', auth()->id())
      ->select(\DB::raw('count(*) as count, state'))
      ->groupBy('state')
      ->get()
      ->flatMap(function ($item) {
        return [
          $item->state => $item->count
        ];
      });

    return success($counts);
  }

  public function failByAdmin($id)
  {
    \DB::transaction(function ($q) use ($id) {

      $buy = Buy::lockForUpdate()->findOrFail($id);
      // $buy->balances()->delete();

      $buy->state = 'fail';
      $buy->save();
      // 用户买币、用户买币佣金、用户买币奖励
      $buy->member->lockForUpdate();
      if ($buy->member->coins < $buy->deposit) {
        fail('用户币值不足');
      }
      $buy->member->coinsChange(-$buy->deposit, '异常订单被扣', $buy->id);

      if ($buy->agent) {
        // 代理佣金、代理奖励
        $buy->agent->lockForUpdate();
        if ($buy->agent->coins < $buy->agent_tip_fee) {
          fail('代理币值不足');
        }
        $buy->agent->coinsChange(-$buy->agent_tip_fee, '异常订单被扣', $buy->id);
      }

      $buy->member->violations()->create([
        'order_id' => $buy->id,
        'seller_id' => $buy->seller_id
      ]);
    });

    return success('ok');
  }

  public function unlockByAdmin($id)
  {
    $buy = Buy::lockForUpdate()->findOrFail($id);

    $buy->clearMember();

    return success('ok');
  }

  public function show($id)
  {
    $buy = Buy::select('id', 'state', 'coins', 'bank', 'bankcard', 'realname', 'fee', 'tip', 'updated_at', 'freeze_at')->findOrFail($id);

    return success($buy);
  }
}
